package com.yingwei.mining.appletversion;

import java.awt.*;
import java.awt.image.ImageObserver;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: yingwei
 * Date: 2009-11-15
 * Time: 21:29:35
 * To change this template use File | Settings | File Templates.
 */
public class Truck extends Device implements Runnable, Drawable
{
    enum TruckStatus { LOAD, WAIT_LOAD, MOVE_TO_LOAD,MOVE_TO_UNLOAD, UNLOAD,WAIT_UNLOAD, WAIT_INSTRUCTION };
    private static int ID_GENERATOR = 1;
    private final static int LOADING_TIME = 1000;
    private final static int UNLOADING_TIME = 30;
    private int adjustedLoadingTime = LOADING_TIME;
    private int adjustedUnLoadingTime = UNLOADING_TIME;
    private TruckStatus truckStatus = TruckStatus.LOAD;
    public TruckStatus getTruckStatus()
    {
        return truckStatus;
    }
    private boolean loaded;
    private double speed;
    private int stepsOnRoute = 0;
    private int stepsLoading = 0;
    private int stepsUnLoading = 0;
    private Instruction instruction;
    private String id;
    private GraphPanel graphPanel;
    
    public GraphPanel getGraphPanel()
    {
        return graphPanel;
    }
    public void setGraphPanel(GraphPanel graphPanel)
    {
        this.graphPanel = graphPanel;
    }
    
    public String getId()
    {
        return id;
    }
    public void setId(String id)
    {
        this.id = id;
    }


    public Truck(Image img, Instruction instruction)
    {
        this();
        setImage(img);
        setInstruction( instruction );
    }
    private Truck()
    {
        id = ""+ID_GENERATOR++;
        setPosition(  new Position(0,0) );
        setSpeed(0.0);
        setLoaded( false );
        setInstruction( null );
        truckStatus = TruckStatus.MOVE_TO_UNLOAD;
        stepsOnRoute = 0;
    }
    public boolean isLoaded() {
        return loaded;
    }

    public void setLoaded(boolean loaded) {
        this.loaded = loaded;
    }

    public double getSpeed() {
        return speed;
    }

    public void setSpeed(double speed) {
        this.speed = speed;
    }

    public Instruction getInstruction() {
        return instruction;
    }

    public void setInstruction(Instruction instruction) {
        this.instruction = instruction;
    }

    public void run()
    {
        int dist = instruction.getRoute().getDistance();
        Edge[] edges = instruction.getRoute().edges;
        int currentLandMarkStart = 0;
        Edge currentEdge = edges[0];
        int relativeSteps = 0;
        for(int i=0;i<edges.length;i++)
        {
            if( stepsOnRoute >= currentLandMarkStart && stepsOnRoute <= currentLandMarkStart + edges[i].len )
            {
        	relativeSteps = stepsOnRoute - currentLandMarkStart;
        	currentEdge = edges[i];
        	break;
            }
            currentLandMarkStart += edges[i].len;
        }
        //Position routeStart = instruction.getRoute().getExcavator().getPosition();
        //Position routeEnd = instruction.getRoute().getUnloadArea().getPosition();
        //System.out.println("dd:" + stepsOnRoute + " relative:" + relativeSteps);
        adjustedLoadingTime = (int)(LOADING_TIME*100.0/instruction.getRoute().getExcavator().getStrength());
        adjustedUnLoadingTime = (int)(UNLOADING_TIME*100.0/instruction.getRoute().getUnloadArea().getStrength());
        switch( truckStatus )
        {
            case MOVE_TO_LOAD:
                if( --stepsOnRoute >= 0 )
                {
                    Node n1 = graphPanel.nodes[currentEdge.to];
                    Node n2 = graphPanel.nodes[currentEdge.from];
                    double dx = n1.x - n2.x;
                    double dy = n1.y - n2.y;
                    int x = (int) (relativeSteps *dx/currentEdge.len + n2.x);
                    int y = (int) (relativeSteps *dy/currentEdge.len + n2.y);
                    setPosition(new Position(x,y));
                }
                else
                {
                    truckStatus = TruckStatus.WAIT_LOAD;
                }
                break;
            case MOVE_TO_UNLOAD:
                if( ++stepsOnRoute <= dist )
                {
                    Node n1 = graphPanel.nodes[currentEdge.to];
                    Node n2 = graphPanel.nodes[currentEdge.from];
                    double dx = n1.x - n2.x;
                    double dy = n1.y - n2.y;
                    int x = (int) (relativeSteps *dx/currentEdge.len + n2.x);
                    int y = (int) (relativeSteps *dy/currentEdge.len + n2.y);
                    setPosition(new Position(x,y));
                }
                else
                {
                    truckStatus = TruckStatus.WAIT_UNLOAD;
                }
                break;
            case LOAD:
                if( stepsLoading++ > adjustedLoadingTime )
                {
                	Excavator ex = instruction.getRoute().getExcavator();
            		ex.setAvailable(true);
                    truckStatus = TruckStatus.MOVE_TO_UNLOAD;
                    stepsLoading = 0;
                    instruction = obtainUnloadInstruction();
                }
                break;
            case WAIT_LOAD:
            	Excavator ex = instruction.getRoute().getExcavator();
            	if( ex.isAvailable() )
            	{
            	    ex.setAvailable(false);
                    truckStatus = TruckStatus.LOAD;
            	}
                break;
            case WAIT_UNLOAD:
                truckStatus = TruckStatus.UNLOAD;
                break;
            case UNLOAD:
                if( stepsUnLoading++ > adjustedUnLoadingTime )
                {
                    truckStatus = TruckStatus.MOVE_TO_LOAD;
                    stepsUnLoading = 0;
                    instruction = obtainLoadInstruction();
                }
                break;
            case WAIT_INSTRUCTION:
                truckStatus = TruckStatus.WAIT_INSTRUCTION;
                break;
            default:
                break;
        }
    }

    public void draw(Graphics g, ImageObserver obsv)
    {
    	/*
    	g.setColor(Color.BLACK);
    	g.setXORMode(Color.BLACK);
    	if( lastX != 0 || lastY != 0 )
    	{
    		// erase the last step image
    		g.drawString("car"+id, lastX,lastY);
    		g.drawRect(lastX,lastY,lastX+2,lastY+2);
            //g.drawImage( this.getImage(), lastX, lastY, obsv );
            lastX = this.getPosition().getX();
            lastY = this.getPosition().getY(); 
    	}
    	*/
		//g.drawString("car"+id, this.getPosition().getX(), this.getPosition().getY());
        //g.drawImage( this.getImage(), this.getPosition().getX(), this.getPosition().getY(), obsv );
        //g.drawString(id,this.getPosition().getX(), this.getPosition().getY());
    	FontMetrics fm = g.getFontMetrics();
	int w = fm.stringWidth(id) + 4;
	int h = fm.getHeight() + 1;
	if( graphPanel.showIcon )
	{
	    g.setColor(Color.black);
	    g.drawImage(this.getImage(), this.getPosition().getX(), this.getPosition().getY(),graphPanel);
	    g.drawString(id, this.getPosition().getX() - (w - 4) / 2, (this
		.getPosition().getY() - (h - 1) / 2)
		+ fm.getAscent());
	}
	else
	{
	    g.setColor( new Color(250, 220, 100) );
	    g.fillRect(this.getPosition().getX() - w / 2, this.getPosition().getY()
		- h / 2, w, h);
	    g.setColor(Color.black);
	    if( truckStatus == TruckStatus.MOVE_TO_UNLOAD )
	    {
		g.drawRect(this.getPosition().getX() - w / 2, this.getPosition().getY()
			- h / 2, w - 1, h - 1);
	    }
	    g.drawString(id, this.getPosition().getX() - (w - 4) / 2, (this
			.getPosition().getY() - (h - 1) / 2)
			+ fm.getAscent());
	}
    }
    private Instruction obtainUnloadInstruction()
    {
        int minDistance = 99999999;
        Route shortestRoute = null;
        Excavator currentEx = instruction.getRoute().getExcavator();

        for( int i=0;i<graphPanel.nroutes; i++ )
        {
            Route rt = graphPanel.routes[i];
            if( currentEx == rt.getExcavator() && rt.getDistance() < minDistance )
            {
                minDistance = rt.getDistance();
                shortestRoute = rt;
            }
        }
        return new Instruction("unloading",shortestRoute);
    }
    private Instruction obtainLoadInstruction()
    {
        int minDistance = 99999999;
        Route shortestRoute = null;
        UnloadArea currentUn = instruction.getRoute().getUnloadArea();

        for( int i=0;i<graphPanel.nroutes; i++ )
        {
            Route rt = graphPanel.routes[i];
            if( rt.getUnloadArea() == currentUn )
            {
                int start = FrameClock.currentSteps + rt.getDistance();
                int end = start + adjustedLoadingTime;
                int nextStart = rt.getExcavator().findNextAvailableSchedule( start, end );
                if( nextStart < minDistance )
                {
                    minDistance = nextStart;
                    shortestRoute = rt;
                }
            }
        }
        shortestRoute.getExcavator().addSchedule(
        		minDistance,
        		minDistance+adjustedLoadingTime);
        // set the stepOnRoute to 100% so that the starting point is from this unload area.
        stepsOnRoute = shortestRoute.getDistance();
        return new Instruction("loading",shortestRoute);
    }
}
